package com.atguigu.gulimall.cart.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.to.SkuInfoTo;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.cart.feign.ProductFeignService;
import com.atguigu.gulimall.cart.interceptor.CartInterceptor;
import com.atguigu.gulimall.cart.service.CartService;
import com.atguigu.gulimall.cart.vo.CartItemVo;
import com.atguigu.gulimall.cart.vo.CartVo;
import com.atguigu.gulimall.cart.vo.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CartServiceImpl implements CartService {
    private final String CART_PREFIX = "gulimall:cart:";

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    @Autowired
    ProductFeignService productFeignService;

    @Autowired
    ThreadPoolExecutor executor;

    @Override
    public CartItemVo addCart(Long skuId, Integer num) {
        BoundHashOperations<String, Object, Object> ops = getOps();

        // 判断redis中是否有该商品，如果有，则数量相加，如果没有，则直接添加
        String cartItemVoStr = (String) ops.get(skuId.toString());
        if (StringUtils.isEmpty(cartItemVoStr)) {
            // 封装CartItemVo，并保存到redis中（多服务远程调用要用异步编排调用）
            CartItemVo cartItemVo = new CartItemVo();

            CompletableFuture<Void> executerSkuInfo =  CompletableFuture.runAsync(() -> {
                // 远程调用获取sku的基础信息
                R info = productFeignService.info(skuId);
                SkuInfoTo skuInfo = info.getData("skuInfo", new TypeReference<SkuInfoTo>() {
                });

                cartItemVo.setSkuId(skuId);
                cartItemVo.setCount(num);
                cartItemVo.setImage(skuInfo.getSkuDefaultImg());
                cartItemVo.setPrice(skuInfo.getPrice());
                cartItemVo.setTitle(skuInfo.getSkuTitle());
            }, executor);

            CompletableFuture<Void> executerSkuAttrs = CompletableFuture.runAsync(() -> {
                R skuSaleAttrValue = productFeignService.getSkuSaleAttrValueBySkuId(skuId);
                List<String> skuSaleAttrValueList = skuSaleAttrValue.getData(new TypeReference<List<String>>() {
                });

                cartItemVo.setSkuAttrs(skuSaleAttrValueList);
            },executor);

            CompletableFuture.allOf(executerSkuInfo, executerSkuAttrs).join();

            ops.put(skuId.toString(), JSONObject.toJSONString(cartItemVo));

            return cartItemVo;
        } else {
            CartItemVo cartItemVo = JSONObject.parseObject(cartItemVoStr, new TypeReference<CartItemVo>() {
            });

            cartItemVo.setCount(cartItemVo.getCount() + num);

            ops.put(skuId.toString(), JSONObject.toJSONString(cartItemVo));
            return cartItemVo;
        }
    }

    @Override
    public CartItemVo getCartItem(Long skuId) {
        BoundHashOperations<String, Object, Object> ops = getOps();

        String cartItemVoStr = (String) ops.get(skuId.toString());

        return JSONObject.parseObject(cartItemVoStr, new TypeReference<CartItemVo>() {
        });
    }

    @Override
    public CartVo getCart() {
        // 获取用户信息
        UserInfoVo userInfoVo = CartInterceptor.threadLocal.get();

        CartVo cartVo = new CartVo();
        List<CartItemVo> tempCartItemVoList = getCartVoByKey(CART_PREFIX + userInfoVo.getUserKey());
        if (userInfoVo.getUserId() != null) {
            // 检查是否有临时用户的购物车信息
            if (!CollectionUtils.isEmpty(tempCartItemVoList)) {
                // 有临时购物车时，将其合并到登录用户的购物车中
                for (CartItemVo cartItemVo : tempCartItemVoList) {
                    addCart(cartItemVo.getSkuId(), cartItemVo.getCount());
                }

                // 删除临时购物车
                redisTemplate.delete(CART_PREFIX + userInfoVo.getUserKey());
            }

            List<CartItemVo> cartItemVoList = getCartVoByKey(CART_PREFIX + userInfoVo.getUserId());
            cartVo.setItems(cartItemVoList);
        } else {
            // 未登录状态获取购物车信息
            cartVo.setItems(tempCartItemVoList);
        }

        return cartVo;
    }

    @Override
    public void checkItem(Long skuId, Integer checked) {
        BoundHashOperations<String, Object, Object> ops = getOps();

        CartItemVo cartItem = this.getCartItem(skuId);
        cartItem.setCheck(checked == 1);

        ops.put(skuId.toString(), JSONObject.toJSONString(cartItem));
    }

    @Override
    public void updateCartItemNum(Long skuId, Integer num) {
        BoundHashOperations<String, Object, Object> ops = getOps();

        CartItemVo cartItem = this.getCartItem(skuId);
        cartItem.setCount(num);

        ops.put(skuId.toString(), JSONObject.toJSONString(cartItem));
    }

    @Override
    public void deleteCartItem(Long skuId) {
        BoundHashOperations<String, Object, Object> ops = getOps();
        ops.delete(skuId.toString());
    }

    private List<CartItemVo> getCartVoByKey(String cartKey) {
        BoundHashOperations<String, Object, Object> ops = redisTemplate.boundHashOps(cartKey);

        List<Object> obj = ops.values();
        if (!CollectionUtils.isEmpty(obj)) {
            return obj.stream().map(item -> {
                return JSONObject.parseObject((String) item, new TypeReference<CartItemVo>() {
                });
            }).collect(Collectors.toList());
        } else {
            return null;
        }
    }

    private BoundHashOperations<String, Object, Object> getOps() {
        // 查询threadlocal中的用户信息，判断加入购物车的商品存在哪个用户下
        UserInfoVo userInfoVo = CartInterceptor.threadLocal.get();

        String cartKey;
        if (userInfoVo.getUserId() != null) {
            cartKey = CART_PREFIX + userInfoVo.getUserId();
        } else {
            cartKey = CART_PREFIX + userInfoVo.getUserKey();
        }

        return redisTemplate.boundHashOps(cartKey);
    }
}
